#include <stdio.h>
#include "sdkconfig.h"

#include "esp_heap_caps.h"
#include "esp_spi_flash.h"
#include "esp_system.h"

#include "lvgl_port.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "audio.h"
#include "nvs_flash.h"
#include "esp_spiffs.h"
#include "i2c_bus2.h"
#include "music.h"
#include "gpio.h"
#include "color.h"
#include "main.h"
#include "storage.h"
#include "wifi.h"
#include "wifi_scan.h"
#include "wifi_scan_page.h"
#include "main_page.h"
#include "lv_symbol_extra_def.h"
#include "weather_page.h"
#include "lvgl_port.h"
#include "lv_port_fs.h"
#include "music_page.h"
#include "task_mag.h"
#include "pwm.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "cJSON.h"
#include "strings.h"
#include "http_time.h"
#include "udp.h"
#include "terminal_page.h"
#include "console.h"

#define TAG "TERMINAL_PAGE"

xQueueHandle terminal_page_queue = NULL;
extern xQueueHandle main_page_queue;

char *console_str2 = NULL;

static lv_obj_t *textarea_console2 = NULL;
static lv_obj_t *console_label2 = NULL;

lv_group_t *group;
static void udp_key_display(char *buf, char key);

/**
 * @brief 退出
 *
 * @param obj 列表对象
 * @param event 列表事件
 */
static void textarea_exit_cb(lv_obj_t *obj, lv_event_t event)
{
    uint32_t page_option_data;

    if (event == LV_EVENT_CLICKED)
    {
        page_option_data = PAGE_EXIT;
        xQueueSend(terminal_page_queue, &page_option_data, NULL);
    }
}

/**
 * @brief 控制台
 *
 * @param sw 打开 true 关闭 false
 * @param ssid 提示输入密码的ssid
 */
static void console_control(uint8_t sw)
{
    static uint32_t init = false;
    static lv_obj_t *textarea_console = NULL;
    static lv_obj_t *console_label = NULL;
    static lv_obj_t *bg_obj = NULL;

    lv_port_sem_take();
    if (sw)
    {
        if (init == false)
        {
            init = true;

            //文本输入
            textarea_console = lv_textarea_create(lv_scr_act(), NULL);
            textarea_console2 = textarea_console;
            lv_obj_set_event_cb(textarea_console, textarea_exit_cb);
            lv_textarea_set_text(textarea_console, "");
            lv_obj_set_size(textarea_console, 260, 35);
            lv_obj_align(textarea_console, NULL, LV_ALIGN_CENTER, 0, 80);

            //终端背景
            bg_obj = lv_obj_create(lv_scr_act(), NULL);
            lv_obj_set_style_local_bg_color(bg_obj, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
            lv_obj_set_size(bg_obj, 260, 150);
            lv_obj_align(bg_obj, NULL, LV_ALIGN_IN_TOP_LEFT, 30, 20);

            //终端
            console_label = lv_label_create(lv_scr_act(), NULL);
            console_label2 = console_label;

            char str[32];
            sprintf(str, "terminal %s,port 1000", TERMINAL_SV);

            lv_label_set_text(console_label, str);
            lv_label_set_long_mode(console_label, LV_LABEL_LONG_BREAK);
            lv_label_set_align(console_label, LV_LABEL_ALIGN_LEFT);
            lv_obj_set_size(console_label, 260 - 5, 150 - 5);
            lv_obj_set_auto_realign(console_label, true);
            lv_obj_align(console_label, NULL, LV_ALIGN_IN_TOP_LEFT, 30 + 5, 20 + 5);
            lv_obj_set_style_local_text_font(console_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &font_en_18);
            lv_obj_set_style_local_text_color(console_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);

            lv_group_remove_all_objs(group);
            lv_group_set_editing(group, true);
            lv_group_add_obj(group, textarea_console2);
        }
    }
    else
    {
        if (init == true)
        {
            init = false;

            lv_obj_del(textarea_console);
            lv_obj_del(console_label);
            lv_obj_del(bg_obj);

            textarea_console2 = NULL;
        }
    }
    lv_port_sem_give();
}

/**
 * @brief 终端显示缓存大小
 *
 * 终端显示范围 一行21字符，共7行，共127个字符
 *
 */
#define CONSOLE_MAX 127
/**
 * @brief 行字符长度
 *
 */
#define CONSOLE_LN_LEN 21
/**
 * @brief 行数
 *
 */
#define CONSOLE_LN 7

/**
 * @brief 向终端增加一行字符串
 *
 * @param buf 缓存
 * @param str 行内容
 */
void console_add_lin(char *buf, char *str)
{
    char *buf2 = buf;
    uint32_t line_feed = 0;

    /**
     * @brief 限制一行长度，注意需要预留结束符和换行符
     *
     */
    if (strlen(str) >= (CONSOLE_LN_LEN - 1))
        return;

    /**
     * @brief 计算当前行数
     *
     */
    for (size_t i = 0; i < CONSOLE_MAX; i++)
    {
        if (buf[i] == '\n')
        {
            line_feed++;
        }
    }

    /**
     * @brief 删除第一行
     *
     */
    if (line_feed >= CONSOLE_LN)
    {
        line_feed = 0;
        for (size_t i = 0; i < CONSOLE_LN_LEN; i++)
        {
            if (buf[i] != '\n')
            {
                line_feed++;
            }
            else
                break;
        }

        uint32_t len = strlen(buf + line_feed + 1);
        memmove(buf, buf + line_feed + 1, len);
        buf[len] = '\0';
    }

    sprintf(buf, "%s%s\n", buf2, str);
    
#if 0
    ESP_LOG_BUFFER_HEXDUMP("MD5", buf, CONSOLE_MAX + 10, ESP_LOG_INFO);
#endif
    lv_port_sem_take();
    lv_label_set_text(console_label2, buf);
    lv_port_sem_give();
}

/**
 * @brief udp缓存长度
 *
 */
#define UDP_INPUT_BUF_LEN 32

/**
 * @brief udp键值显示
 *
 * @param buf 字符串缓存
 * @param key 键值
 */
static void udp_key_display(char *buf, char key)
{
    uint32_t page_option_data;
    char *buf2 = buf;

    if (textarea_console2)
    {
        switch (key)
        {
        case '\r': //回车
            console_handle(buf);
            break;
        case '\b': //退格
            if (strlen(buf) != 0)
            {
                buf[strlen(buf) - 1] = '\0';
                lv_textarea_set_text(textarea_console2, buf);
            }
            break;
        default: //其他键值
            sprintf(buf, "%s%c", buf2, key);
            lv_textarea_set_text(textarea_console2, buf);
            break;
        }
    }
}

/**
 *
 * @brief 页面任务
 *
 */
void terminal_page_task()
{
    uint32_t page_option_data;
    char *console_str = NULL;
    char key_str[UDP_INPUT_BUF_LEN];

    memset(key_str, 0, sizeof(key_str));
    console_str = malloc(CONSOLE_MAX + 10);
    console_str2 = console_str;
    memset(console_str, '\0', CONSOLE_MAX + 10);

    while (1)
    {
        if (xQueueReceive(terminal_page_queue, &page_option_data, portMAX_DELAY))
        {
            /**
             * @brief udp键值事件
             *
             * @param terminal_page_queue
             */
            if (PAGE_UDP_KEY_MASK & page_option_data)
            {
                udp_key_display(key_str, (char)page_option_data);
                continue;
            }

            switch (page_option_data)
            {
            case PAGE_SHOW:
                wallpaper_init(WALLPAPER_BLACK);
                console_control(true);
                break;
            case PAGE_EXIT:
                console_control(false);

                free(console_str);
                vTaskDelay(200 / portTICK_RATE_MS);
                page_option_data = PAGE_SHOW;
                xQueueSend(main_page_queue, &page_option_data, NULL);

                cql_page_dele(TERMINAL_PAGE_TASK_NUM);
                break;
            case PAGE_LEFT_KEY:
                ESP_LOGE(TAG, "收到键值 左");

                console_add_lin(console_str, "Hello world!");
                lv_port_sem_give();
                break;
            case PAGE_RIGHT_KEY:
                ESP_LOGE(TAG, "收到键值 右");

                console_add_lin(console_str, "Welcome!");
                lv_port_sem_give();
                break;
            case PAGE_CLEAN_CONSOLE:
                ESP_LOGE(TAG, "清空终端");

                lv_port_sem_take();
                memset(console_str, '\0', CONSOLE_MAX + 10);
                lv_label_set_text(console_label2, "");
                memset(key_str, 0, UDP_INPUT_BUF_LEN);
                lv_textarea_set_text(textarea_console2, key_str);
                lv_port_sem_give();
                break;
            case PAGE_CLEAN_CONSOLE_INPUT:
                ESP_LOGE(TAG, "清空输入");

                lv_port_sem_take();
                memset(key_str, 0, UDP_INPUT_BUF_LEN);
                lv_textarea_set_text(textarea_console2, key_str);
                lv_port_sem_give();
                break;
            default:

                break;
            }
        }
    }
}
